use std::path::PathBuf;
use std::process::{exit, Command};

use crate::core::builder::{self, Builder, RunConfig, ShouldRun, Step};
use crate::core::builder::Cargo as CargoCommand;
use crate::utils::exec::BootstrapCommand;

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
struct ToolBuild {
    tool: &'static str,
    path: &'static str,
    extra_features: Vec<String>,
}

impl Step for ToolBuild {
    type Output = PathBuf;

    fn should_run(run: builder::ShouldRun<'_>) -> builder::ShouldRun<'_> {
        run.never()
    }

    fn run(self, builder: &builder::Builder<'_>) -> Self::Output {
        let tool = self.tool;
        let path = self.path;

        let cargo = prepare_tool_cargp(
            builder, 
            path, 
            &self.extra_features
        );
        print!("tool: {:?}", tool);
        let mut cargo = Command::from(cargo);
        let build_success = builder.run_cmd(BootstrapCommand::from(&mut cargo).allow_failure());
        if !build_success {
            exit(1);
        } else {
            let cargo_out = builder.config.src.join(path).join("target");
            cargo_out
        }
    }
}

fn prepare_tool_cargp(
    builder: &Builder<'_>,
    path: &str,
    extra_features: &[String]
) -> CargoCommand {
    let mut cargo = builder::Cargo::new(builder);
    
    let dir = builder.config.src.join(path);
    cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));

    let features = extra_features.to_vec();
    if !features.is_empty() {
        cargo.arg("--features").arg(&features.join(", "));
    }
    cargo
}

#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Hash)]
pub struct RustDummy;

impl Step for RustDummy {
    type Output = PathBuf;

    fn run(self, builder: &Builder<'_>) -> Self::Output {
        builder.ensure(ToolBuild {
            tool: "rust-dummy",
            path: "tools/rust-dummy",
            extra_features: Vec::new(),
        })
    }

    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
        run.path("tools/rust-dummy")
    }
    
    fn make_run(run: RunConfig<'_>) {
        run.builder.ensure(RustDummy );
    }
}